#ifndef	_J_VRIJEME_H
#define	_J_VRIJEME_H

#include "tipovi.h"
#include "postavke.h"
#include <arh/vrijeme.h>

#define BR1E9	1000000000 /* koliko nanosekundi ima u sekundi */

//! Vrijednost djeljitelja frekvencije sata
#define	SAT_BROJILO	((SAT_FREKVENCIJA + HZ / 2) / HZ)


//sucelje prema ostatku sustava
void	j_sat_inicijaliziraj (); //za pocetnu dretvu

//sucelje za programe, tj. za sloj "sucelje"
int	j_alarm_postavi (void *param);
int	j_alarm_obrisi (void *param);

//parametri za novi alarm (koriste se u komunikaciji "sucelje" => "jezgra")
typedef struct _alarm_t_ {
	int		id;	//id alarma, 0 ako se trazi novi

	vrijeme_t	kada;	//kad se treba "probuditi"?
				//relativno u odnosu na j_sat-a, ili apsolutno

	void		(*obrada)(void *);//funkcija koja se zove po isteku
	void		*param;		//parametar koji se salje u funkciju

	int		zast;		//razne zastavice
} alarm_t;

#define	PERIODICKI	0x01	//alarm se ponavlja periodicki
#define	STVORINOVI	0x02	//stvori novi alarm
#define BLOKIRAJDR	0x04	//blokiraj dretvu (ne koristi se)

#define	ABSVRIJEME	0x08	//zadano vrijeme je absolutno u odnosu na j_sat
#define	RELVRIJEME	0x00	//zadano vrijeme je relativno prema j_sat-u

#ifdef	_J_VRIJEME_C_

//struktura za svaki alarm (podaci podsustava "vrijeme")
typedef struct _jalarm_ {
	vrijeme_t	period;		//koliko odbrojava
	vrijeme_t	budjenje;	//kad se treba "probuditi"
					// * apsolutno vrijeme j_sat-a
	bool		periodicki;	//da li se alarm ponavlja po isteku?

	void		(*obrada)(void *);//funkcija koja se zove po isteku
	void		*param;		//parametar koji se salje u funkciju

	union {
		int	zast;		//razne zastavice,
		int	slobodno;	//-1 ako je ovaj alarm slobodan
	};

	int		red;		//red u kojem cekaju dretve na alarm

	struct _jalarm_	*iduci;		//iduci alarm u listi aktivnih alarma
} j_alarm_t;

//lista alarma
typedef struct _jalarmi_ {
	j_alarm_t *prvi;
	j_alarm_t *zadnji;
} j_alarmi_t;

//pomocne funkcije za rad sa strukturom vrijeme_t
static inline vrijeme_t j_vrijeme_zbroji (vrijeme_t x, vrijeme_t y)
{
	vrijeme_t z;

	z.sekunde  = x.sekunde  + y.sekunde;
	z.nsekunde = x.nsekunde + y.nsekunde;

	if (z.nsekunde >= BR1E9) {
		z.sekunde++;
		z.nsekunde -= BR1E9;
	}
	
	return z;
}

static inline vrijeme_t j_vrijeme_oduzmi (vrijeme_t x, vrijeme_t y)
{//pretpostavlja x >= y i ne provjerava!
	vrijeme_t z;

	z.sekunde = x.sekunde - y.sekunde;

	if (x.nsekunde >= y.nsekunde) {
		z.nsekunde = x.nsekunde - y.nsekunde;
	}
	else {
		z.sekunde--;
		z.nsekunde = BR1E9 + x.nsekunde - y.nsekunde;
	}
	
	return z;
}

/* vraca 0 ako je x == y, -1 ako je x < y i 1 ako ne x > y */
static inline int j_vrijeme_usporedi(vrijeme_t x, vrijeme_t y)
{ 
	if ( x.sekunde == y.sekunde && x.nsekunde == y.nsekunde )
		return 0;

	if ( x.sekunde < y.sekunde || 
		(x.sekunde == y.sekunde && x.nsekunde < y.nsekunde) )
		return -1;

	return 1;
}

static int j_alarm_usporedi (j_alarm_t *x, j_alarm_t *y);

//interne pomocne funkcije
static int j_alarm_stvori ();
static void j_alarm_azuriraj_sat ();
static void j_sat_prekid (int x);


#endif /* _J_VRIJEME_C_ */
#endif	/* _J_VRIJEME_H */